""" 
various webhelpers template tags, taken from Pylons

copyright: Arvis Bickovskis 2007 
viestards.lists@gmail.com

Pylons webhelpers: http://pylonshq.com/WebHelpers/index.html
Ruby on Rails helpers: http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html

"""




from django import template
from webhelpers import *
#from djangohelpers import rails as django
from django.template import Library,Node

register = template.Library()
var_separator=":" # how separate variables from values in templatetags
_framework=1

#--------------------------------------
# functions, that needed to be clear

    
class HelpersNode(template.Node):
    def __init__(self, widget_code):
        #print widget_code
        self.widget_code= widget_code
    def render(self, context):
        return self.widget_code    
        
def script_visual_effect(parser, token):
    """Adds various JS visual effects to chosen element
    {% visual_effect Highlight model1 duration:15 %}
    """
    #print parser, token
    args = token.split_contents()
    if len(args)<3:
        # checking for arg count
        raise template.TemplateSyntaxError, "%r tag requires at least two arguments" % token.contents[0]
    args_dict={}
    # if there is additional arguments, convert from list to dict
    if len(args)>3:
        args_dict=list_to_dict(args[3:])
    wigdet=rails.scriptaculous.visual_effect(args[1],args[2],**args_dict)
    return HelpersNode(wigdet)

def script_sortable_element(parser, token):
    """ 
    sortable_element(element_id, **options)
    Port of sortable_element
    """
    _framework=2
    arg_values=['element_id']
    return generate_args(parser, token,'sortable_element',arg_values)
    
    
def script_draggable_element(parser, token):
    """ draggable_element(element_id, **options):
        port of helpers draggable element
    """
    _framework=2
    arg_values=['element_id']
    return generate_args(parser, token,'draggable_element',arg_values)

# Prototype functions
#-------------------------------------------------------    
def rails_remote_function(parser, token):
    """
    implementation of Pylons remote function
    link_to_remote(name, options={})
        
    for docs look into http://pylonshq.com/WebHelpers/module-webhelpers.rails.prototype.html#link_to_remote
    TODO: write doctests
    >>> remote_function({'url': 'pong', 'update': 'pongbox'})
    new Ajax.Updater('pongbox', 'pong', {asynchronous:true, evalScripts:true}); 
    # If I need to implement exacly the samy behavior as webhelpers, i need inclusion templatetag,
    but I don't know if it is better.
    """
    # TODO: chech for errors if incorrect separator KeyError
    args = token.split_contents()
    if len(args)<3:
        # checking for arg count
        raise template.TemplateSyntaxError, "%r tag requires at least two arguments" % token.contents[0]
    try:
        widget=rails.prototype.remote_function(**list_to_dict(args[1:]))
    except KeyError: # if incorrect conversion to dict, return nothing
        raise template.TemplateSyntaxError, "tag incorrect parameters in tag %r" % token.contents[0]
    #return HelpersNode(wigdet)
    # Proof of concept way,
    return ProofOfConceptNode('remote_function',list_to_dict(args[1:]))

def rails_form_remote_tag(parser, token):
    """
    Examples:
    form_remote_tag(**{'url': 'pong', 'update': 'pongbox'})
    '<form action="pong" method="post" onsubmit="new Ajax.Updater(\'pongbox\', \'pong\', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">'    
    """ 
    args=token.split_contents()
    # TODO: check for argument count
    try:    
        widget=list_to_dict(args[1:])
    except KeyError: # if incorrect conversion to dict, return nothing
        raise template.TemplateSyntaxError, "tag incorrect parameters in tag %r" % token.contents[0]
    return ProofOfConceptNode('form_remote_tag',widget)
    
def rails_submit_to_remote(parser, token):
    """ submit_to_remote tag 
    def submit_to_remote(name, value, **options):

    #>>> rails.prototype.submit_to_remote('name','value',**{'url': 'pong', 'update': 'pongbox'})
    #>>> '<input name="1" onclick="new Ajax.Updater(\'pongbox\', \'pong\', {asynchronous:true,   evalScripts:true,parameters:Form.serialize(this.form)}); return false;" type="button" value="2" />'
    """
    arg_values=['name', 'value']
    return generate_args(parser, token,'submit_to_remote',arg_values)
    
def rails_observe_field(parser, token):
    """
    observe field helper
    >>> rails.prototype.observe_field('1',**{'url': 'pong', 'update': 'pongbox'})
    >>> '<script type="text/javascript">\n//<![CDATA[\nnew Form.Element.EventObs
    erver(\'1\', function(element, value) {new Ajax.Updater(\'pongbox\', \'pong\', {
    asynchronous:true, evalScripts:true})})\n//]]>\n</script>'
    def observe_field(field_id, **options):
    """
    arg_values=['field_id']
    return generate_args(parser, token,'observe_field',arg_values)
    
def rails_observe_form(parser, token):   
    """
    port to observe form
    #def observe_form(form_id, **options):
    """
    arg_values=['form_id']
    return generate_args(parser, token,'observe_form',arg_values)

def rails_link_to_remote(parser, token):
    """
    def link_to_remote(name, options={}, **html_options):
    """
    #FIXME: there is some problem with this function, have to return to it later
    arg_values=['name']
    args = token.split_contents()
    # take first argument- templatetag out
    args=args[1:]
    if len(args)<1:
        raise template.TemplateSyntaxError, "%r tag requires at 1 argument" % token.contents[0]
    
    #<a href="#" onclick="{% helper function_name:remote_function url:/frets/shell/ update:pongbox success:test_funct() %}; return false;">ping</a> 
    return generate_args(parser, token,'remote_function',arg_values,'<a href="#" onclick="',';return false;">'+args[0]+'</a>') 


def rails_periodically_call_remote(parser, token):
    """
    def periodically_call_remote(**options):
    """
    return generate_args(parser, token,'periodically_call_remote')




# -------------------
#generic class that creates JavaScript    
class ProofOfConceptNode(template.Node):
    "this is not recomended way, it is only now to show proof of concept"
    def __init__(self, function_name,args,html_before="",html_after=""):
        """
        function_name- function that will be called with getattr
        args- arguments for webhelpers function passed as dictionary
        # FIXME: html must be taken somewhere else, it is temporary
        html_before-html code right before templatetag
        html_after- html code right after templatetag
        """
        #print widget_code
        self.widget_code= args
        self.function=function_name
        self.before=html_before
        self.after=html_after
        
    def render(self, context):
        # FIXME: wrong way of rendering, now implemented only as proof of concept

        #FIXME: lame way of setting modules
        if _framework>1:
            function_class=rails.scriptaculous
        else:
            function_class=rails.prototype
            
        widget=getattr(function_class,self.function)(**self.widget_code)
        widget=self.before+widget+self.after
        #return getattr(rails.prototype,self.function)(**self.widget_code)
        return widget



        
# -----------------------------------------------------
# support functions

def generate_args(parser, token, function_name="", arg_keys=[],html_before="",html_after=""):
    """genereating variables from tokens
    standartaaa pirmie n mainiigie ir noteiktie, paareejie, ir neobligaati un tiek padoti kaa dict
    parser, token, arg_keys
    arg_keys- list of mandatory argument keys
    """
    args = token.split_contents()
    # take first argument- templatetag out
    args=args[1:]
    
    if len(args)<len(arg_keys):
        raise template.TemplateSyntaxError, "%r tag requires at %i arguments" % (token.contents[0],mandatory_args)
    
    # formeejam f-jas izsaukumu, tiem, kuriem nav pielikti keys, pieliekam tos
    # TODO: think, if it is not better to allways have keys 
    for i in range(0,len(arg_keys)):
        args[i]=arg_keys[i]+var_separator+args[i]
    
    #convert to dictionary variables, that are not mandatory
    #  patreiz visi izsaukiem jaabuut ar key, lai vienkaarsaak paarveerst
    #print "**",args,arg_keys
    args_dict=list_to_dict(args)

    if len(function_name)==0:
        function_name=args_dict['function_name']

    return ProofOfConceptNode(function_name,args_dict,html_before,html_after)

    
def list_to_dict(li):
    """
    converts list to dictionary
    """
    # TODO: may be need to cut fist list member here
    
    # in case of empty list return empty dict
    
    if len(li)==0:
        return {}
    try:
        full_args=[]
        # TODO: add error handling
        for args in li:
            # TODO: if there is no separator, just add arg1 or something like that
             full_args.append(args.split(var_separator))
        #    print dict(full_args)
        return dict(full_args)    
    except ValueError:
        # need to have some kind of traceback
        #print "value error"#,li
        return {}  # die silently



    
def create_form_tag(parser, token,function_name):
    """
    common function to call rails helpers.
    parser, token- standart templatefilters arguments
    function_name- wihich helper function will be called
    """
    # TODO: check for argument count
    try:    
        #print "**",args
        widget=list_to_dict(args[1:])
    except KeyError: # if incorrect conversion to dict, return nothing
        raise template.TemplateSyntaxError, "tag incorrect parameters in tag %r" % token.contents[0]
    return ProofOfConceptNode(function_name,widget)
        
#register.filter('js_header', js_header)


# active functions
# effect function
register.tag('visual_effect', script_visual_effect)

# protoype functions
register.tag('helper', generate_args)
register.tag('remote_function', rails_remote_function)
register.tag('form_remote_tag', rails_form_remote_tag)
register.tag('submit_to_remote', rails_submit_to_remote)
register.tag('periodically_call_remote', rails_periodically_call_remote)

# FIXME: return to this function later
register.tag('link_to_remote', rails_link_to_remote)

register.tag('observe_form', rails_observe_form)
register.tag('observe_field', rails_observe_field)


